#ifndef CODEDOCUMENT_h
#define CODEDOCUMENT_h

#include "Settings/StorageSettings.h"
#include "Settings/TabSettings.h"

#include "ICodeEditor.h" // ITextMarkable
#include "IFile.h" // Core::IFile

QT_BEGIN_NAMESPACE
class QTextCursor;
class QTextDocument;
class QSyntaxHighlighter;
QT_END_NAMESPACE

namespace CodeEdit {

class DocumentMarker : public ITextMarkable
{
    Q_OBJECT

public:
    DocumentMarker(QTextDocument *);

    // ITextMarkable
    bool addMark(ITextMark *mark, int line);
    TextMarks marksAt(int line) const;
    void removeMark(ITextMark *mark);
    bool hasMark(ITextMark *mark) const;
    void updateMark(ITextMark *mark);

private:
    QTextDocument *_document;
};

/**
 * @class FileDocument
 * FileDocument wraps the text document (QTextDocument).
 * It is responsible for loading and saving the text document and takes care of
 * text codec.
 */
class FileDocument : public Core::IFile
{
    Q_OBJECT

public:
    FileDocument();
    ~FileDocument();

    inline void setStorageSettings(const StorageSettings &storageSettings) { _storageSettings = storageSettings; }
    inline void setTabSettings(const TabSettings &tabSettings) { _tabSettings = tabSettings; }

    inline const StorageSettings &storageSettings() const { return _storageSettings; }
    inline const TabSettings &tabSettings() const { return _tabSettings; }

    inline DocumentMarker *documentMarker() const { return _documentMarker; }

    // IFile
    virtual bool save(const QString &fileName = QString());
    virtual QString fileName() const { return _fileName; }

    virtual QString defaultPath() const { return _defaultPath; }
    virtual QString suggestedFileName() const { return _suggestedFileName; }

    virtual bool isModified() const;
    virtual bool isReadOnly() const;
    virtual bool isSaveAsAllowed() const { return true; }
    virtual void checkPermissions();

    virtual ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const;
    virtual void reload(ReloadFlag flag, ChangeType type);
    virtual void rename(const QString &newName);
    // end IFile

    virtual QString mimeType() const;
    void setMimeType(const QString &mt);

    void setDefaultPath(const QString &defaultPath) { _defaultPath = defaultPath; }
    void setSuggestedFileName(const QString &suggestedFileName) { _suggestedFileName = suggestedFileName; }

    virtual bool open(const QString &fileName = QString());
    virtual void reload();

    QTextDocument *document() const { return _document; }
    void setSyntaxHighlighter(QSyntaxHighlighter *highlighter);
    QSyntaxHighlighter *syntaxHighlighter() const { return _highlighter; }

    inline bool isBinaryData() const { return _isBinaryData; }
    inline bool hasDecodingError() const { return _hasDecodingError || _isBinaryData; }
    inline QTextCodec *codec() const { return _codec; }
    inline void setCodec(QTextCodec *c) { _codec = c; }
    inline QByteArray decodingErrorSample() const { return _decodingErrorSample; }

    void reload(QTextCodec *codec);

    void cleanWhitespace(const QTextCursor &cursor);

signals:
    void titleChanged(QString title);
    void aboutToReload();
    void reloaded();

private:
    QString _fileName;
    QString _defaultPath;
    QString _suggestedFileName;
    QString _mimeType;
    StorageSettings _storageSettings;
    TabSettings _tabSettings;
    QTextDocument *_document;
    DocumentMarker *_documentMarker;
    QSyntaxHighlighter *_highlighter;

    enum LineTerminatorMode {
        LFLineTerminator,
        CRLFLineTerminator,
        NativeLineTerminator =
#ifdef Q_OS_WIN
        CRLFLineTerminator
#else
        LFLineTerminator
#endif
    };
    LineTerminatorMode _lineTerminatorMode;
    QTextCodec *_codec;

    bool _fileIsReadOnly;
    bool _isBinaryData;
    bool _hasDecodingError;
    QByteArray _decodingErrorSample;

    void cleanWhitespace(QTextCursor& cursor, bool cleanIndentation, bool inEntireDocument);
    void ensureFinalNewLine(QTextCursor& cursor);
};

} // namespace CodeEdit

#endif // CODEDOCUMENT_h
